/******************************************************************************
 *
 * MotionViewer
 * Copyright (C) 2007 Sangyoon Lee, Electronic Visualization Laboratory, 
 * University of Illinois at Chicago
 *
 * This software is free software; you can redistribute it and/or modify it 
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either Version 2.1 of the License, or 
 * (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
 * License for more details.
 * 
 * You should have received a copy of the GNU Lesser Public License along
 * with this software; if not, write to the Free Software Foundation, Inc., 
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 * Questions or comments about MotionViewer should be directed to 
 * cavern@evl.uic.edu
 *
 *****************************************************************************/
/*
-----------------------------------------------------------------------------
Filename:    MotionViewer.cpp
-----------------------------------------------------------------------------

This source file is generated by the Ogre AppWizard.

Check out: http://conglomerate.berlios.de/wiki/doku.php?id=ogrewizards

Based on the Example Framework for OGRE
(Object-oriented Graphics Rendering Engine)

Copyright (c) 2000-2007 The OGRE Team
For the latest info, see http://www.ogre3d.org/

You may use this sample code for anything you like, it is not covered by the
LGPL like the rest of the OGRE engine.
-----------------------------------------------------------------------------
*/
#include <iostream>
#include <ogreplatform.h>
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
#include <Carbon/Carbon.h>
#endif


#include "CEGUICommonFileDialog.h"
#include "ViconRTData.h"
#include "ViconRTVisualizer.h"
#include "ViconVFileData.h"
#include "ViconVVisualizer.h"
#include "MocapVisualizer.h"
#include "ViconCharacter.h"
#include "ViconSubject.h"
#include "ConfigFile.h"

#include "MotionViewer.h"

// GUI: file loader caller definition
#define LOAD_CHARACTER	0
#define LOAD_VSKFILEV	1 
#define LOAD_VFILE		2
#define LOAD_VSKFILERT	3
#define LOAD_MAPFILE	4

//------------------------------------------------------------------------------
MotionViewerApp::MotionViewerApp(void)
{
	m_iCurrDataSetSelected = -1;
	m_iCurrCharacterSelected = -1;
	m_iMapLoaderDataSetSelected = -1;
	m_iCurrDataSetColorItem = 1;
}
//------------------------------------------------------------------------------
MotionViewerApp::~MotionViewerApp(void)
{
	delete m_pVisualizer;

	int num = m_vViconVisualizers.size();
	for (int i=0; i< num; i++)
	{
		delete m_vViconVisualizers[i];
	}
	m_vViconVisualizers.clear();

}

//------------------------------------------------------------------------------
void MotionViewerApp::createScene(void)
{
	// setup GUI system
	mGUIRenderer = new CEGUI::OgreCEGUIRenderer(mWindow,
	 Ogre::RENDER_QUEUE_OVERLAY, false, 3000, mSceneMgr);

	mGUISystem = new CEGUI::System(mGUIRenderer);

	CEGUI::Logger::getSingleton().setLoggingLevel(CEGUI::Informative);


	// load scheme and set up defaults
	CEGUI::SchemeManager::getSingleton().loadScheme(
	 (CEGUI::utf8*)"TaharezLookSkin.scheme");
	CEGUI::SchemeManager::getSingleton().loadScheme((CEGUI::utf8*)"motionviewer.scheme");
	mGUISystem->setDefaultMouseCursor(
	 (CEGUI::utf8*)"TaharezLook", (CEGUI::utf8*)"MouseArrow");
	mGUISystem->setDefaultFont((CEGUI::utf8*)"BlueHighway-12");
	CEGUI::MouseCursor::getSingleton().setImage("TaharezLook", "MouseArrow");
	CEGUI::MouseCursor::getSingleton().show( );
	
	// Load GUI Layout
	CEGUI::Window* editorGuiSheet = CEGUI::WindowManager::getSingleton().loadWindowLayout(
                (CEGUI::utf8*)"MotionViewer_gui.layout"); 
    mGUISystem->setGUISheet(editorGuiSheet);
	
	// Add the common file dialog window to the main window
	CEGUI::Window* mainWindow = CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root");
	CEGUI::Window* dialog = CEGUI::CommonFileDialog::getSingleton().getWindow();
	mainWindow->addChildWindow(dialog);
	
	// assign combobox object
	m_pCharacterCombobox = (CEGUI::Combobox*)CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/Character/SetList");
	m_pMotionCombobox = (CEGUI::Combobox*)CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/DataSet/SetList");
	m_pMotionConnectionCombobox = (CEGUI::Combobox*)CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/ConnectMotionData/SetList");

	// motion data color control
	m_pColorSample = CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/DataSet/ColourSample");
	m_pRed   = static_cast<CEGUI::Scrollbar*>(CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/DataSet/Red"));
	m_pGreen = static_cast<CEGUI::Scrollbar*>(CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/DataSet/Green"));
	m_pBlue  = static_cast<CEGUI::Scrollbar*>(CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/DataSet/Blue"));

	setupEventHandlers();
	
	headNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();

	// Set ambient light
	mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));

	// Create a light
	Light* l = mSceneMgr->createLight("MainLight");
	l->setPosition(20,80,50);
	l->setType(Ogre::Light::LT_DIRECTIONAL);
	l->setDirection(-3, -2, -1);
	SceneNode* lightnode = headNode->createChildSceneNode("main_light_node");
	lightnode->attachObject(l);
	l = mSceneMgr->createLight("MainLight2");
	l->setType(Ogre::Light::LT_DIRECTIONAL);
	l->setDirection(3, -4, -1);
	lightnode->attachObject(l);

	m_pVisualizer = new MocapVisualizer(mSceneMgr, headNode);

	// Adjust Camera
	mCamera->setPosition(0, 180, 440);
	mCamera->lookAt(Ogre::Vector3(0, 10, 0));
	pCameraController = mSceneMgr->getRootSceneNode()->createChildSceneNode();
	pCameraController->attachObject(mCamera);


}

void MotionViewerApp::addCharacter(char* filename)
{
	// create character
	ViconCharacter vc(mSceneMgr, headNode);
	if (!vc.createCharacter(filename))
	{
		// not proper character mesh!!! show up warning message
		CEGUI::String text;
		text = "      ";
		text += filename;
		text += "\n      is not a proper character mesh file!\n      Please make sure your mesh is rigged character!";
		CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/Warning/Text")->setText(text);
		CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/Warning/Window")->show();

		return;
	}
	
	// add to vector
	m_vCharacters.push_back(vc);

	// add list item in combo GUI
	CEGUI::String name(vc.getName());
	CEGUI::ListboxTextItem* item = new CEGUI::ListboxTextItem(name, vc.getID());
	m_pCharacterCombobox->addItem(item);

	// reset variables
	m_iCurrCharacterSelected = vc.getID();
	
	// select newly created motion data in combobox
	m_pCharacterCombobox->setItemSelectState(item, true);
	m_pCharacterCombobox->setText(item->getText());
	m_pCharacterCombobox->handleUpdatedListItemData( ); 
	m_pCharacterCombobox->requestRedraw( );

}

//------------------------------------------------------------------------------
bool MotionViewerApp::frameStarted(const FrameEvent& evt)
{
	if(mWindow->isClosed())
		return false;

	float addedTime = evt.timeSinceLastFrame;

	// update motion dataset
	int vnum = m_vViconVisualizers.size();
	for (int i=0; i < vnum; i++)
		m_vViconVisualizers[i]->update(addedTime);
	
	// update character
	for(m_itrCharacter = m_vCharacters.begin(); m_itrCharacter != m_vCharacters.end(); m_itrCharacter++)
		m_itrCharacter->update(addedTime);

	// update vicon debug text
	//OverlayElement* guiDbg = OverlayManager::getSingleton().getOverlayElement("LifeLike/DebugText");
	//guiDbg->setCaption(m_pViconVVisualizer->getDebugBodyInfo());

	//Need to capture / update each device
	mKeyboard->capture();
	mMouse->capture();

	mUseBufferedInputMouse = mMouse->buffered();
	mUseBufferedInputKeys = mKeyboard->buffered();


      if(mUseBufferedInputMouse)
      {
         CEGUI::MouseCursor::getSingleton().show( );
      }
      else
      {
         CEGUI::MouseCursor::getSingleton().hide( );
      }

	if ( !mUseBufferedInputMouse || !mUseBufferedInputKeys)
	{
		// one of the input modes is immediate, so setup what is needed for immediate mouse/key movement
		if (mTimeUntilNextToggle >= 0)
			mTimeUntilNextToggle -= evt.timeSinceLastFrame;

		// If this is the first frame, pick a speed
		if (evt.timeSinceLastFrame == 0)
		{
			mMoveScale = 1;
			mRotScale = 0.1;
		}
		// Otherwise scale movement units by time passed since last frame
		else
		{
			// Move about 100 units per second,
			mMoveScale = mMoveSpeed * evt.timeSinceLastFrame;
			// Take about 10 seconds for full rotation
			mRotScale = mRotateSpeed * evt.timeSinceLastFrame;
		}
		mRotX = 0;
		mRotY = 0;
		mTranslateVector = Vector3::ZERO;
	}

	if (mUseBufferedInputKeys)
	{
		// no need to do any processing here, it is handled by event processor and
		// you get the results as KeyEvents
	}
	else
	{
		if (processUnbufferedKeyInput(evt) == false)
		{
			return false;
		}
	}
	if (mUseBufferedInputMouse)
	{
		// no need to do any processing here, it is handled by event processor and
		// you get the results as MouseEvents
	}
	else
	{
		if (processUnbufferedMouseInput(evt) == false)
		{
			return false;
		}
	}

	if ( !mUseBufferedInputMouse || !mUseBufferedInputKeys)
	{
		// one of the input modes is immediate, so update the movement vector

		moveCamera();

	}

	return true;
}

//------------------------------------------------------------------------------
bool MotionViewerApp::mouseMoved( const OIS::MouseEvent &arg )
{
	CEGUI::System::getSingleton().injectMouseMove( arg.state.X.rel, arg.state.Y.rel );
	
	static const float mul = 0.5;
	// rotation
	if (mShouldRotate) 
	{
		Quaternion deltaq;
		Real delta, dy, dx;
		Vector3 cmaRight, camDir;
		if (dy = arg.state.Y.rel) 
		{
			delta = dy * mul;
			deltaq.FromAngleAxis(Degree(delta), Vector3::UNIT_X);
			headNode->rotate(mCamera->getRight(), Degree(delta), Ogre::Node::TS_WORLD);
		}

		if (dx = arg.state.X.rel) 
		{
			delta = dx * mul;
			deltaq.FromAngleAxis(Degree(delta), Vector3::UNIT_Y);
			headNode->rotate(Ogre::Vector3(0,1,0), Degree(delta), Ogre::Node::TS_LOCAL);

		}
	}
	// translation
	else if (mShouldTranslate) 
	{
		// move camera instead of root node
		mCamera->moveRelative(Vector3(-arg.state.X.rel*mul, arg.state.Y.rel*mul, 0));
	}
	// zoom
	else if (mShouldZoom)
	{
		// move camera instead of root node
		mCamera->moveRelative(Vector3(0, 0 , -arg.state.Y.rel*mul));
	}
	// another zoom for wheel
	else if (mAltDown && arg.state.Z.rel !=0)
	{
		// move camera instead of root node
		mCamera->moveRelative(Vector3(0, 0 , -arg.state.Z.rel*mul));
	}

	return true;
}

//------------------------------------------------------------------------------
bool MotionViewerApp::processUnbufferedKeyInput(const FrameEvent& evt)
{
	using namespace OIS;
	OIS::Keyboard* mInputDevice = mKeyboard; // Nice hack, eh? :)

	// reload configuration file
	if (mInputDevice->isKeyDown(KC_PERIOD))
	{
		std::cout << "Reloading band config file: " << BandConfigFile::reload() << "\n";
		std::cout << "Updating performers..." << endl;
		this->updatePerformers();
	}
	
	if (mInputDevice->isKeyDown(KC_A))
	{
		// Move camera left
		mTranslateVector.x = -mMoveScale;
	}

	if (mInputDevice->isKeyDown(KC_D))
	{
		// Move camera RIGHT
		mTranslateVector.x = mMoveScale;
	}

	/* Move camera forward by keypress. */
	if (mInputDevice->isKeyDown(KC_UP) || mInputDevice->isKeyDown(KC_W) )
	{
		mTranslateVector.z = -mMoveScale;
	}

	/* Move camera backward by keypress. */
	if (mInputDevice->isKeyDown(KC_DOWN) || mInputDevice->isKeyDown(KC_S) )
	{
		mTranslateVector.z = mMoveScale;
	}

	if (mInputDevice->isKeyDown(KC_PGUP))
	{
		// Move camera up
		mTranslateVector.y = mMoveScale;
	}

	if (mInputDevice->isKeyDown(KC_PGDOWN))
	{
		// Move camera down
		mTranslateVector.y = -mMoveScale;
	}

	if (mInputDevice->isKeyDown(KC_RIGHT))
	{
		mCamera->yaw(-mRotScale);
	}

	if (mInputDevice->isKeyDown(KC_LEFT))
	{
		mCamera->yaw(mRotScale);
	}

	if( mInputDevice->isKeyDown( KC_ESCAPE) )
	{
		return false;
	}

	// see if switching is on, and you want to toggle
	if (mInputTypeSwitchingOn && mInputDevice->isKeyDown(KC_M) && mTimeUntilNextToggle <= 0)
	{
		switchMouseMode();
		mTimeUntilNextToggle = 1;
	}

	if (mInputTypeSwitchingOn && mInputDevice->isKeyDown(KC_K) && mTimeUntilNextToggle <= 0)
	{
		// must be going from immediate keyboard to buffered keyboard
		switchKeyMode();
		mTimeUntilNextToggle = 1;
	}
	if (mInputDevice->isKeyDown(KC_F) && mTimeUntilNextToggle <= 0)
	{
		mStatsOn = !mStatsOn;
		showDebugOverlay(mStatsOn);

		mTimeUntilNextToggle = 1;
	}
	if (mInputDevice->isKeyDown(KC_T) && mTimeUntilNextToggle <= 0)
	{
		switch(mFiltering)
		{
		case TFO_BILINEAR:
			mFiltering = TFO_TRILINEAR;
			mAniso = 1;
			break;
		case TFO_TRILINEAR:
			mFiltering = TFO_ANISOTROPIC;
			mAniso = 8;
			break;
		case TFO_ANISOTROPIC:
			mFiltering = TFO_BILINEAR;
			mAniso = 1;
			break;
		default:
			break;
		}
		MaterialManager::getSingleton().setDefaultTextureFiltering(mFiltering);
		MaterialManager::getSingleton().setDefaultAnisotropy(mAniso);


		showDebugOverlay(mStatsOn);

		mTimeUntilNextToggle = 1;
	}

	if (mInputDevice->isKeyDown(KC_SYSRQ) && mTimeUntilNextToggle <= 0)
	{
		std::ostringstream ss;
		ss << "screenshot_" << ++mNumScreenShots << ".png";
		mWindow->writeContentsToFile(ss.str());
		mTimeUntilNextToggle = 0.5;
		mDebugText = "Saved: " + ss.str();
	}

	if (mInputDevice->isKeyDown(KC_R) && mTimeUntilNextToggle <=0)
	{
		mSceneDetailIndex = (mSceneDetailIndex+1)%3 ;
		switch(mSceneDetailIndex) {
				case 0 : mCamera->setPolygonMode(PM_SOLID) ; break ;
				case 1 : mCamera->setPolygonMode(PM_WIREFRAME) ; break ;
				case 2 : mCamera->setPolygonMode(PM_POINTS) ; break ;
		}
		mTimeUntilNextToggle = 0.5;
	}

	static bool displayCameraDetails = false;
	if (mInputDevice->isKeyDown(KC_P) && mTimeUntilNextToggle <= 0)
	{
		displayCameraDetails = !displayCameraDetails;
		mTimeUntilNextToggle = 0.5;
		if (!displayCameraDetails)
			mDebugText = "";
	}
	if (displayCameraDetails)
	{
		// Print camera details
		mDebugText = "P: " + StringConverter::toString(mCamera->getDerivedPosition()) +
			" " + "O: " + StringConverter::toString(mCamera->getDerivedOrientation());
	}

	// alt key
	if (mInputDevice->isKeyDown(KC_LMENU))
		mAltDown = true;
	else
		mAltDown = false;

	if (mInputDevice->isKeyDown(KC_NUMPAD1) && mTimeUntilNextToggle <= 0)
	{
		m_pViconRTVisualizer->toggleMarkerVisible();
		mTimeUntilNextToggle = 0.5;
	}
	if (mInputDevice->isKeyDown(KC_NUMPAD2) && mTimeUntilNextToggle <= 0)
	{
		m_pViconRTVisualizer->toggleBodyDrawingTypes(BT_BODY);
		mTimeUntilNextToggle = 0.5;
	}
	if (mInputDevice->isKeyDown(KC_NUMPAD3) && mTimeUntilNextToggle <= 0)
	{
		m_pViconRTVisualizer->toggleBodyDrawingTypes(BT_AXIS);
		mTimeUntilNextToggle = 0.5;
	}

	if (mInputDevice->isKeyDown(KC_ADD) && mTimeUntilNextToggle <= 0)
	{
		m_pViconVVisualizer->getDataSet()->increaseSpeed();
	}
	if (mInputDevice->isKeyDown(KC_SUBTRACT) && mTimeUntilNextToggle <= 0)
	{
		m_pViconVVisualizer->getDataSet()->decreaseSpeed();
	}

	// Return true to continue rendering
	return true;
}

void MotionViewerApp::setupEventHandlers(void)
{
	/***************************************************************************
	 * Step 2: Register the function that must be called in case the common file 
	 * dialog has been closed by:
	 **************************************************************************/
	CEGUI::CommonFileDialog::getSingleton().getWindow()->subscribeEvent (CEGUI::FrameWindow::EventHidden, CEGUI::Event::Subscriber(&MotionViewerApp::handleFileDialogOutput, this));

	CEGUI::WindowManager& wmgr = CEGUI::WindowManager::getSingleton();
    
	////////////////////////////////////////////////////////////////////////////
	// Main Menu
	wmgr.getWindow((CEGUI::utf8*)"Root/Base")
			->subscribeEvent(
				CEGUI::FrameWindow::EventRollupToggled, 
				CEGUI::Event::Subscriber(&MotionViewerApp::handleMenuRollUpChanged, this));

	wmgr.getWindow((CEGUI::utf8*)"Root/Warning/CloseButton")
			->subscribeEvent(
				CEGUI::PushButton::EventClicked,
				CEGUI::Event::Subscriber(&MotionViewerApp::handleWarningClose, this));

	// some trick for keyboard buffering
	// if mouse is in other gui component, then buffered (proess key event via gui)
	// otherwise (in transparent area), use unbuffered
	wmgr.getWindow((CEGUI::utf8*)"Root")
			->subscribeEvent(
			CEGUI::FrameWindow::EventMouseEnters, 
				CEGUI::Event::Subscriber(&MotionViewerApp::handleTextInputExit, this));
	wmgr.getWindow((CEGUI::utf8*)"Root")
			->subscribeEvent(
			CEGUI::FrameWindow::EventMouseLeaves, 
				CEGUI::Event::Subscriber(&MotionViewerApp::handleTextInputFocused, this));

	// MotionData Tab
	wmgr.getWindow((CEGUI::utf8*)"Root/DataSet/LoadVButton")
			->subscribeEvent(
				CEGUI::PushButton::EventClicked, 
				CEGUI::Event::Subscriber(&MotionViewerApp::handleNewVFile, this));
	
	wmgr.getWindow((CEGUI::utf8*)"Root/DataSet/LoadRTButton")
			->subscribeEvent(
				CEGUI::PushButton::EventClicked, 
				CEGUI::Event::Subscriber(&MotionViewerApp::handleNewRT, this));
	
	wmgr.getWindow((CEGUI::utf8*)"Root/DataSet/SetList")
			->subscribeEvent(
				CEGUI::Combobox::EventListSelectionAccepted, 
				CEGUI::Event::Subscriber(&MotionViewerApp::handleDataSetSelection, this));
	wmgr.getWindow((CEGUI::utf8*)"Root/DataSet/SetList")
			->subscribeEvent(
				CEGUI::Combobox::EventListSelectionChanged, 
				CEGUI::Event::Subscriber(&MotionViewerApp::handleDataSetSelection, this));

	wmgr.getWindow((CEGUI::utf8*)"Root/DataSet/OffsetX")
			->subscribeEvent(
				CEGUI::Editbox::EventTextAccepted, 
				CEGUI::Event::Subscriber(&MotionViewerApp::handleDataSetOffset, this));
	wmgr.getWindow((CEGUI::utf8*)"Root/DataSet/OffsetY")
			->subscribeEvent(
				CEGUI::Editbox::EventTextAccepted, 
				CEGUI::Event::Subscriber(&MotionViewerApp::handleDataSetOffset, this));
	wmgr.getWindow((CEGUI::utf8*)"Root/DataSet/OffsetZ")
			->subscribeEvent(
				CEGUI::Editbox::EventTextAccepted, 
				CEGUI::Event::Subscriber(&MotionViewerApp::handleDataSetOffset, this));

	wmgr.getWindow((CEGUI::utf8*)"Root/DataSet/SpeedControls")
			->subscribeEvent(
				CEGUI::Scrollbar::EventScrollPositionChanged, 
				CEGUI::Event::Subscriber(&MotionViewerApp::handleDataSetSpeed, this));

	CEGUI::RadioButton* radio;
	radio = static_cast<CEGUI::RadioButton*>(wmgr.getWindow((CEGUI::utf8*)"Root/DataSet/MarkerColor"));
	radio->subscribeEvent(CEGUI::RadioButton::EventSelectStateChanged, 
							CEGUI::Event::Subscriber(&MotionViewerApp::handleColorItemSelected, this));
	radio->setID(1);
	radio->setSelected(true);
	radio = static_cast<CEGUI::RadioButton*>(wmgr.getWindow((CEGUI::utf8*)"Root/DataSet/BodyColor"));
	radio->subscribeEvent(CEGUI::RadioButton::EventSelectStateChanged, 
							CEGUI::Event::Subscriber(&MotionViewerApp::handleColorItemSelected, this));
	radio->setID(2);

	m_pRed->subscribeEvent(
				CEGUI::Scrollbar::EventScrollPositionChanged, 
				CEGUI::Event::Subscriber(&MotionViewerApp::handleColorChanged, this));
	m_pGreen->subscribeEvent(
				CEGUI::Scrollbar::EventScrollPositionChanged, 
				CEGUI::Event::Subscriber(&MotionViewerApp::handleColorChanged, this));
	m_pBlue->subscribeEvent(
				CEGUI::Scrollbar::EventScrollPositionChanged, 
				CEGUI::Event::Subscriber(&MotionViewerApp::handleColorChanged, this));

	////////////////////////////////////////////////////////////////////////////
	// Character Tab
	wmgr.getWindow((CEGUI::utf8*)"Root/Character/CreateCharacterButton")
			->subscribeEvent(
				CEGUI::PushButton::EventClicked, 
				CEGUI::Event::Subscriber(&MotionViewerApp::handleNewCharacter, this));
	wmgr.getWindow((CEGUI::utf8*)"Root/Character/ChangeMotionDataButton")
			->subscribeEvent(
				CEGUI::PushButton::EventClicked, 
				CEGUI::Event::Subscriber(&MotionViewerApp::handleSetMapping, this));
	wmgr.getWindow((CEGUI::utf8*)"Root/Character/SetList")
			->subscribeEvent(
				CEGUI::Combobox::EventListSelectionAccepted, 
				CEGUI::Event::Subscriber(&MotionViewerApp::handleCharacterSelection, this));
	wmgr.getWindow((CEGUI::utf8*)"Root/Character/SetList")
			->subscribeEvent(
				CEGUI::Combobox::EventListSelectionChanged, 
				CEGUI::Event::Subscriber(&MotionViewerApp::handleCharacterSelection, this));
	wmgr.getWindow((CEGUI::utf8*)"Root/Character/OffsetX")
			->subscribeEvent(
				CEGUI::Editbox::EventTextAccepted, 
				CEGUI::Event::Subscriber(&MotionViewerApp::handleCharacterOffset, this));
	wmgr.getWindow((CEGUI::utf8*)"Root/Character/OffsetY")
			->subscribeEvent(
				CEGUI::Editbox::EventTextAccepted, 
				CEGUI::Event::Subscriber(&MotionViewerApp::handleCharacterOffset, this));
	wmgr.getWindow((CEGUI::utf8*)"Root/Character/OffsetZ")
			->subscribeEvent(
				CEGUI::Editbox::EventTextAccepted, 
				CEGUI::Event::Subscriber(&MotionViewerApp::handleCharacterOffset, this));

	////////////////////////////////////////////////////////////////////////////
	// v file loader gui
	wmgr.getWindow((CEGUI::utf8*)"Root/LoadVFile/VSKLoadButton")
			->subscribeEvent(
				CEGUI::PushButton::EventClicked, 
				CEGUI::Event::Subscriber(&MotionViewerApp::handleVFileVSK, this));
	wmgr.getWindow((CEGUI::utf8*)"Root/LoadVFile/VLoadButton")
			->subscribeEvent(
				CEGUI::PushButton::EventClicked, 
				CEGUI::Event::Subscriber(&MotionViewerApp::handleVFileV, this));
	wmgr.getWindow((CEGUI::utf8*)"Root/LoadVFile/CancelButton")
			->subscribeEvent(
				CEGUI::PushButton::EventClicked, 
				CEGUI::Event::Subscriber(&MotionViewerApp::handleVFileLoaderCancel, this));
	wmgr.getWindow((CEGUI::utf8*)"Root/LoadVFile/OkButton")
			->subscribeEvent(
				CEGUI::PushButton::EventClicked, 
				CEGUI::Event::Subscriber(&MotionViewerApp::handleVFileLoaderOK, this));
	wmgr.getWindow((CEGUI::utf8*)"Root/LoadVFile")
			->subscribeEvent(
				CEGUI::FrameWindow::EventCloseClicked, 
				CEGUI::Event::Subscriber(&MotionViewerApp::handleVFileClose, this));

	////////////////////////////////////////////////////////////////////////////
	// rt connector gui
	wmgr.getWindow((CEGUI::utf8*)"Root/ConnectRT/VSKLoadButton")
			->subscribeEvent(
				CEGUI::PushButton::EventClicked, 
				CEGUI::Event::Subscriber(&MotionViewerApp::handleRTLoaderVSK, this));
	wmgr.getWindow((CEGUI::utf8*)"Root/ConnectRT/CancelButton")
			->subscribeEvent(
				CEGUI::PushButton::EventClicked, 
				CEGUI::Event::Subscriber(&MotionViewerApp::handleRTLoaderCancel, this));
	wmgr.getWindow((CEGUI::utf8*)"Root/ConnectRT/OkButton")
			->subscribeEvent(
				CEGUI::PushButton::EventClicked, 
				CEGUI::Event::Subscriber(&MotionViewerApp::handleRTLoaderOK, this));
	wmgr.getWindow((CEGUI::utf8*)"Root/ConnectRT")
			->subscribeEvent(
				CEGUI::FrameWindow::EventCloseClicked, 
				CEGUI::Event::Subscriber(&MotionViewerApp::handleRTLoaderClose, this));
	
	////////////////////////////////////////////////////////////////////////////
	// map file loader gui
	wmgr.getWindow((CEGUI::utf8*)"Root/ConnectMotionData/SetList")
			->subscribeEvent(
				CEGUI::Combobox::EventListSelectionAccepted, 
				CEGUI::Event::Subscriber(&MotionViewerApp::handleMapLoaderDataSet, this));
	wmgr.getWindow((CEGUI::utf8*)"Root/ConnectMotionData/MapLoadButton")
			->subscribeEvent(
				CEGUI::PushButton::EventClicked, 
				CEGUI::Event::Subscriber(&MotionViewerApp::handleMapLoaderMap, this));
	wmgr.getWindow((CEGUI::utf8*)"Root/ConnectMotionData/CancelButton")
			->subscribeEvent(
				CEGUI::PushButton::EventClicked, 
				CEGUI::Event::Subscriber(&MotionViewerApp::handleMapLoaderCancel, this));
	wmgr.getWindow((CEGUI::utf8*)"Root/ConnectMotionData/OkButton")
			->subscribeEvent(
				CEGUI::PushButton::EventClicked, 
				CEGUI::Event::Subscriber(&MotionViewerApp::handleMapLoaderOK, this));
	wmgr.getWindow((CEGUI::utf8*)"Root/ConnectMotionData")
			->subscribeEvent(
				CEGUI::FrameWindow::EventCloseClicked, 
				CEGUI::Event::Subscriber(&MotionViewerApp::handleMapLoaderClose, this));

	// Let's roll up main menu window at the beginning
	static_cast<CEGUI::FrameWindow*>(wmgr.getWindow("Root/Base"))->toggleRollup();
}

bool MotionViewerApp::handleLoad(const CEGUI::EventArgs& e)
{
	/***************************************************************************
	Step 3a: Call the file dialog with the input data
	***************************************************************************/
	CEGUI::CommonFileDialogInput input;
	input.setHandle (1);										// Set the handle to determine the originator
	input.setFilter ("Archive (*.zip)|*.zip|All files|*.*|");	// Extensions
	input.setOpenFileDialog (true);								// Load mode
	input.setDefaultExtension ("*.zip");						// Zip is the first one to display
	CEGUI::CommonFileDialog::getSingleton().openDialog(input);	// Open the common file dialog
	return true;

	
}

bool MotionViewerApp::handleFileDialogOutput(const CEGUI::EventArgs& e)
{
	CEGUI::CommonFileDialogOutput result = CEGUI::CommonFileDialog::getSingleton().getResult();
	if (result.getAction() == CEGUI::ACTION_OK)
	{
		CEGUI::String filename;
		filename = result.getAbsolutePath();
#if  OGRE_PLATFORM == OGRE_PLATFORM_WIN32		
		filename = filename + "\\" + result.getFileName();
#else
		filename = filename + "/" + result.getFileName();
#endif
		switch (result.getHandle())
		{
		case LOAD_CHARACTER:
			// Character	: model -> dataset -> mapping
			addCharacter((char*)filename.c_str());
			break;
		case LOAD_VSKFILEV:
			m_sSubjectFile = std::string(filename.c_str());
			CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/LoadVFile/VSKFile")->setText(filename);
			break;
		case LOAD_VFILE:
			m_sViconFile = std::string(filename.c_str());
			CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/LoadVFile/VFile")->setText(filename);
			break;
		case LOAD_VSKFILERT:
			m_sSubjectFile = std::string(filename.c_str());
			CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/ConnectRT/VSKFile")->setText(filename);
			break;
		case LOAD_MAPFILE:
			m_sMapFile = std::string(filename.c_str());
			CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/ConnectMotionData/MapFile")->setText(filename);
			break;

		}

	}

	return true;
}

/*******************************************************************************
* GUI event handler
*******************************************************************************/
bool MotionViewerApp::handleMenuRollUpChanged(const CEGUI::EventArgs& e)
{
	CEGUI::FrameWindow* menu = (CEGUI::FrameWindow*)CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/Base");
	CEGUI::TabControl* tab = (CEGUI::TabControl*)CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/TabCtrl");
	
	if (menu->isRolledup())
		tab->hide();
	else
		tab->show();

	return true;
}

bool MotionViewerApp::handleTextInputFocused(const CEGUI::EventArgs& e)
{
	mUseBufferedInputKeys = true;
	mKeyboard->setBuffered(mUseBufferedInputKeys);

	return true;
}

bool MotionViewerApp::handleTextInputExit(const CEGUI::EventArgs& e)
{
	mUseBufferedInputKeys = false;
	mKeyboard->setBuffered(mUseBufferedInputKeys);

	return true;
}

bool MotionViewerApp::handleWarningClose(const CEGUI::EventArgs& e)
{
	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/Warning/Window")->hide();
	return true;
}

bool MotionViewerApp::handleNewVFile(const CEGUI::EventArgs& e)
{
	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/LoadVFile")->show();
	
	return true;
}

bool MotionViewerApp::handleNewRT(const CEGUI::EventArgs& e)
{
	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/ConnectRT")->show();

	return true;
}

bool MotionViewerApp::handleDataSetSelection(const CEGUI::EventArgs& e)
{
	const CEGUI::WindowEventArgs& windowEventArgs = static_cast<const CEGUI::WindowEventArgs&>(e);
	CEGUI::Combobox* box = static_cast<CEGUI::Combobox*>(windowEventArgs.window);
	CEGUI::ListboxItem* item = box->getSelectedItem();

	if (item == NULL)
		return true;

	int idx = box->getItemIndex(item);

	if (idx < 0 || idx > m_vViconVisualizers.size()-1)
		return true;

	m_iCurrDataSetSelected = idx;

	// need to find following information from vector of ViconVisulizer
	// type, subject file, framerate, frames, speed, offset
	float offset[3];
	MOTION_TYPE type	= m_vViconVisualizers[idx]->getDataSet()->getType();
	std::string subject = m_vViconVisualizers[idx]->getDataSet()->getSubjectFileName();
	float rate			= m_vViconVisualizers[idx]->getDataSet()->getFrameRate();
	int frames			= m_vViconVisualizers[idx]->getDataSet()->getTotalFrames();
	float speed			= m_vViconVisualizers[idx]->getDataSet()->getSpeed();
	m_vViconVisualizers[idx]->getPosition(offset);

	char str[64];
	CEGUI::String text;
	if (type == MT_RTENGINE)
	{
		sprintf(str, "Type: %s", "RealTime");
		CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/DataSet/SpeedControls")->disable();
	}
	else if (type == MT_VFILE)
	{
		sprintf(str, "Type: %s", "Vicon File");
		CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/DataSet/SpeedControls")->enable();
	}

	text = str;
	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/DataSet/SetInfoTypeLabel")->setText(text);
	
	sprintf(str, "Subject File: %s", subject.c_str()); text = str;
	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/DataSet/SetInfoSubjectLabel")->setText(text);
	
	sprintf(str, "FrameRate: %5.1f", rate); text = str;
	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/DataSet/SetInfoRateLabel")->setText(text);
	
	sprintf(str, "Total Frames: %i", frames); text = str;
	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/DataSet/SetInfoFrameLabel")->setText(text);
	
	sprintf(str, "Speed:: %4.2f", speed); text = str;
	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/DataSet/SetInfoSpeedLabel")->setText(text);
	CEGUI::Scrollbar* bar = (CEGUI::Scrollbar*)CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/DataSet/SpeedControls");
	bar->setScrollPosition(speed);

	sprintf(str, "%6.1f", offset[0]); text = str;
	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/DataSet/OffsetX")->setText(text);
	sprintf(str, "%6.1f", offset[1]); text = str;
	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/DataSet/OffsetY")->setText(text);
	sprintf(str, "%6.1f", offset[2]); text = str;
	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/DataSet/OffsetZ")->setText(text);

	// colors
	using namespace CEGUI;
	WindowManager& winMgr = WindowManager::getSingleton();
	EventArgs eventArgs;
	static_cast<RadioButton*>(winMgr.getWindow("Root/DataSet/MarkerColor"))->fireEvent(RadioButton::EventSelectStateChanged, eventArgs);

	return true;
}

bool MotionViewerApp::handleDataSetOffset(const CEGUI::EventArgs& e)
{
	float pos[3];
	pos[0] = atof(CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/DataSet/OffsetX")->getText().c_str());
	pos[1] = atof(CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/DataSet/OffsetY")->getText().c_str());
	pos[2] = atof(CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/DataSet/OffsetZ")->getText().c_str());

	if (m_iCurrDataSetSelected != -1)
		m_vViconVisualizers[m_iCurrDataSetSelected]->setPosition(pos[0], pos[1], pos[2]);

	mUseBufferedInputKeys = false;
	mKeyboard->setBuffered(mUseBufferedInputKeys);

	return true;
}

bool MotionViewerApp::handleDataSetSpeed(const CEGUI::EventArgs& e)
{
	CEGUI::Scrollbar* bar = (CEGUI::Scrollbar*)CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/DataSet/SpeedControls");
	float value = bar->getScrollPosition();
	char str[64];
	sprintf(str, "Speed: %4.2f", value);
	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/DataSet/SetInfoSpeedLabel")->setText(str);

	// Set motiondata speed as value
	if (m_iCurrDataSetSelected != -1)
		m_vViconVisualizers[m_iCurrDataSetSelected]->getDataSet()->setSpeed(value);

	return true;
}

bool MotionViewerApp::handleColorItemSelected(const CEGUI::EventArgs& e)
{
	CEGUI::uint id = static_cast<CEGUI::RadioButton*>
		(CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/DataSet/MarkerColor"))->getSelectedButtonInGroup()->getID();
	
	m_iCurrDataSetColorItem = id;

	if (m_iCurrDataSetSelected < 0)
		return true;

	if (id == 1)
	{
		Ogre::ColourValue color = m_vViconVisualizers[m_iCurrDataSetSelected]->getMarkerColor();
		m_pRed->setScrollPosition(color[0]*255.0f);
		m_pGreen->setScrollPosition(color[1]*255.0f);
		m_pBlue->setScrollPosition(color[2]*255.0f);
	}
	else if (id == 2)
	{
		Ogre::ColourValue color = m_vViconVisualizers[m_iCurrDataSetSelected]->getBodyColor();
		m_pRed->setScrollPosition(color[0]*255.0f);
		m_pGreen->setScrollPosition(color[1]*255.0f);
		m_pBlue->setScrollPosition(color[2]*255.0f);
	}

	return true;
}

bool MotionViewerApp::handleColorChanged(const CEGUI::EventArgs& e)
{
	if (m_iCurrDataSetSelected < 0)
		return true;

	// retrieve color value
	float r = m_pRed->getScrollPosition() / 255.0f;
	float g = m_pGreen->getScrollPosition() / 255.0f;
	float b = m_pBlue->getScrollPosition() / 255.0f;

    m_pColorSample->setProperty("ImageColours",
    CEGUI::PropertyHelper::colourToString(CEGUI::colour(r, g, b)));

	if (m_iCurrDataSetColorItem == 1)
	{
		// change marker color
		m_vViconVisualizers[m_iCurrDataSetSelected]->setMarkerColor(r, g, b, 1);
	}
	else if (m_iCurrDataSetColorItem ==2)
	{
		// change body color
		m_vViconVisualizers[m_iCurrDataSetSelected]->setBodyColor(r, g, b, 1);
	}

	return true;

}

// Character Tab
bool MotionViewerApp::handleNewCharacter(const CEGUI::EventArgs& e)
{
	// TODO: load up file dialog here
	CEGUI::CommonFileDialogInput input;
	input.setHandle (LOAD_CHARACTER);								// Set the handle to determine the originator
	input.setFilter ("Ogre Mesh (*.mesh)|*.mesh|All files|*.*|");	// Extensions
	input.setOpenFileDialog (true);									// Load mode
	input.setDefaultExtension ("*.mesh");							// Mesh is the first one to display
	CEGUI::CommonFileDialog::getSingleton().openDialog(input);		// Open the common file dialog

	return true;
}

bool MotionViewerApp::handleSetMapping(const CEGUI::EventArgs& e)
{
	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/ConnectMotionData")->show();

	return true;
}

bool MotionViewerApp::handleCharacterSelection(const CEGUI::EventArgs& e)
{
	const CEGUI::WindowEventArgs& windowEventArgs = static_cast<const CEGUI::WindowEventArgs&>(e);
	CEGUI::Combobox* box = static_cast<CEGUI::Combobox*>(windowEventArgs.window);
	CEGUI::ListboxItem* item = box->getSelectedItem();

	if (item == NULL)
		return true;

	int idx = box->getItemIndex(item);

	if (idx < 0 || idx > m_vCharacters.size() -1)
		return true;

	m_iCurrCharacterSelected = idx;

	// update Character tab information
	// name, map file, triangles, bones, connected motion, offset
	float offset[3];
	std::string name	= m_vCharacters[idx].getName();
	std::string map		= m_vCharacters[idx].getMapFileName();
	int bone			= m_vCharacters[idx].getNumBones();
	ViconMotionDataSet* dataset = m_vCharacters[idx].getDataSet();
	std::string data;
	if (dataset)
		data = dataset->getName();
	else
		data = "N/A";
	m_vCharacters[idx].getPosition(offset);

	char str[64];
	CEGUI::String text;
	sprintf(str, "Name: %s", name.c_str()); text = str;
	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/Character/NameLabel")->setText(text);
	
	sprintf(str, "Mapping File: %s", map.c_str()); text = str;
	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/Character/MappingLabel")->setText(text);
	
	sprintf(str, "Total Bones: %i", bone); text = str;
	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/Character/BonesLabel")->setText(text);
	
	sprintf(str, "Connected Motion:: %s", data.c_str()); text = str;
	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/Character/MotionDataLabel")->setText(text);
	
	sprintf(str, "%6.1f", offset[0]); text = str;
	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/Character/OffsetX")->setText(text);
	sprintf(str, "%6.1f", offset[1]); text = str;
	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/Character/OffsetY")->setText(text);
	sprintf(str, "%6.1f", offset[2]); text = str;
	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/Character/OffsetZ")->setText(text);
	
	return true;
}

bool MotionViewerApp::handleCharacterOffset(const CEGUI::EventArgs& e)
{
	float pos[3];
	pos[0] = atof(CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/Character/OffsetX")->getText().c_str());
	pos[1] = atof(CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/Character/OffsetY")->getText().c_str());
	pos[2] = atof(CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/Character/OffsetZ")->getText().c_str());

	if (m_iCurrCharacterSelected != -1)
		m_vCharacters[m_iCurrCharacterSelected].setPosition(pos[0], pos[1], pos[2]);

	mUseBufferedInputKeys = false;

	return true;
}


// v file loader gui
bool MotionViewerApp::handleVFileVSK(const CEGUI::EventArgs& e)
{
	// TODO: load up file dialog here
	CEGUI::CommonFileDialogInput input;
	input.setHandle (LOAD_VSKFILEV);								// Set the handle to determine the originator
	input.setFilter ("Vicon Subject (*.vsk)|*.vsk|All files|*.*|");	// Extensions
	input.setOpenFileDialog (true);									// Load mode
	input.setDefaultExtension ("*.vsk");							// Mesh is the first one to display
	CEGUI::CommonFileDialog::getSingleton().openDialog(input);		// Open the common file dialog

	return true;
}

bool MotionViewerApp::handleVFileV(const CEGUI::EventArgs& e)
{
	// TODO: load up file dialog here
	CEGUI::CommonFileDialogInput input;
	input.setHandle (LOAD_VFILE);								// Set the handle to determine the originator
	input.setFilter ("Vicon V (*.v)|*.v|All files|*.*|");		// Extensions
	input.setOpenFileDialog (true);								// Load mode
	input.setDefaultExtension ("*.v");							// Mesh is the first one to display
	CEGUI::CommonFileDialog::getSingleton().openDialog(input);	// Open the common file dialog

	return true;
}

bool MotionViewerApp::handleVFileLoaderCancel(const CEGUI::EventArgs& e)
{
	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/LoadVFile")->hide();
	
	// reset variables
	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/LoadVFile/VFile")->setText("N/A");
	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/LoadVFile/VSKFile")->setText("N/A");
	m_sViconFile = "";
	m_sSubjectFile = "";

	return true;
}

bool MotionViewerApp::handleVFileLoaderOK(const CEGUI::EventArgs& e)
{
	// process new v file
	ViconVVisualizer* vis = new ViconVVisualizer(mSceneMgr, headNode);
	vis->createScene((char*)m_sViconFile.c_str());
	vis->getDataSet()->loadSubject("Subject", (char*)m_sSubjectFile.c_str());
	m_vViconVisualizers.push_back(vis);

	// add list item in combo GUI
	CEGUI::String name(vis->getDataSet()->getName());
	CEGUI::ListboxTextItem* item = new CEGUI::ListboxTextItem(name, vis->getID());
	m_pMotionCombobox->addItem(item);
	CEGUI::ListboxTextItem* item1 = new CEGUI::ListboxTextItem(name, vis->getID());
	m_pMotionConnectionCombobox->addItem(item1);

	// reset variables
	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/LoadVFile/VFile")->setText("N/A");
	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/LoadVFile/VSKFile")->setText("N/A");
	m_sViconFile = "";
	m_sSubjectFile = "";

	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/LoadVFile")->hide();
	
	// select newly created motion data in combobox
	m_pMotionCombobox->setItemSelectState(item, true);
	m_pMotionCombobox->setText(item->getText());
	m_pMotionCombobox->handleUpdatedListItemData( ); 
	m_pMotionCombobox->requestRedraw( );

	return true;
}

bool MotionViewerApp::handleVFileClose(const CEGUI::EventArgs& e)
{
	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/LoadVFile")->hide();

	// reset variables
	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/LoadVFile/VFile")->setText("N/A");
	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/LoadVFile/VSKFile")->setText("N/A");
	m_sViconFile = "";
	m_sSubjectFile = "";

	return true;
}

// rt connector gui
bool MotionViewerApp::handleRTLoaderVSK(const CEGUI::EventArgs& e)
{
	// TODO: load up file dialog here
	CEGUI::CommonFileDialogInput input;
	input.setHandle (LOAD_VSKFILERT);								// Set the handle to determine the originator
	input.setFilter ("Vicon Subject (*.vsk)|*.vsk|All files|*.*|");	// Extensions
	input.setOpenFileDialog (true);									// Load mode
	input.setDefaultExtension ("*.vsk");							// Mesh is the first one to display
	CEGUI::CommonFileDialog::getSingleton().openDialog(input);		// Open the common file dialog

	return true;
}

bool MotionViewerApp::handleRTLoaderCancel(const CEGUI::EventArgs& e)
{
	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/ConnectRT")->hide();

	// reset variables
	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/ConnectRT/RTAddr")->setText("");
	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/ConnectRT/VSKFile")->setText("N/A");
	m_sRTAddress = "";
	m_sSubjectFile = "";

	return true;
}

bool MotionViewerApp::handleRTLoaderOK(const CEGUI::EventArgs& e)
{
	// process new RT connection
	m_sRTAddress = CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/ConnectRT/RTAddr")->getText().c_str();
	ViconRTVisualizer* vis = new ViconRTVisualizer(mSceneMgr, headNode);
	vis->createScene((char*)m_sRTAddress.c_str());
	vis->getDataSet()->loadSubject("Subject", (char*)m_sSubjectFile.c_str());
	m_vViconVisualizers.push_back(vis);

	// add list item in combo GUI
	CEGUI::String name(vis->getDataSet()->getName());
	CEGUI::ListboxTextItem* item = new CEGUI::ListboxTextItem(name, vis->getID());
	m_pMotionCombobox->addItem(item);
	CEGUI::ListboxTextItem* item1 = new CEGUI::ListboxTextItem(name, vis->getID());
	m_pMotionConnectionCombobox->addItem(item1);

	// reset variables
	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/ConnectRT/RTAddr")->setText("");
	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/ConnectRT/VSKFile")->setText("N/A");
	m_sRTAddress = "";
	m_sSubjectFile = "";
	
	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/ConnectRT")->hide();

	// select newly created motion data in combobox
	m_pMotionCombobox->setItemSelectState(item, true);
	m_pMotionCombobox->setText(item->getText());
	m_pMotionCombobox->handleUpdatedListItemData( ); 
	m_pMotionCombobox->requestRedraw( );

	return true;

}

bool MotionViewerApp::handleRTLoaderClose(const CEGUI::EventArgs& e)
{
	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/ConnectRT")->hide();

	// reset variables
	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/ConnectRT/RTAddr")->setText("");
	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/ConnectRT/VSKFile")->setText("N/A");
	m_sRTAddress = "";
	m_sSubjectFile = "";

	return true;
}


// map file loader gui
bool MotionViewerApp::handleMapLoaderDataSet(const CEGUI::EventArgs& e)
{
	const CEGUI::WindowEventArgs& windowEventArgs = static_cast<const CEGUI::WindowEventArgs&>(e);
	CEGUI::Combobox* box = static_cast<CEGUI::Combobox*>(windowEventArgs.window);
	CEGUI::ListboxItem* item = box->getSelectedItem();
	int idx = box->getItemIndex(item);

	if (idx < 0)
		return true;

	m_iMapLoaderDataSetSelected = idx;

	return true;
}

bool MotionViewerApp::handleMapLoaderMap(const CEGUI::EventArgs& e)
{
	// TODO: load up file dialog here
	CEGUI::CommonFileDialogInput input;
	input.setHandle (LOAD_MAPFILE);									// Set the handle to determine the originator
	input.setFilter ("Bone Mapping (*.map)|*.map|All files|*.*|");	// Extensions
	input.setOpenFileDialog (true);									// Load mode
	input.setDefaultExtension ("*.map");							// Mesh is the first one to display
	CEGUI::CommonFileDialog::getSingleton().openDialog(input);		// Open the common file dialog

	return true;
}

bool MotionViewerApp::handleMapLoaderCancel(const CEGUI::EventArgs& e)
{
	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/ConnectMotionData")->hide();

	// reset variables
	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/ConnectMotionData/MapFile")->setText("N/A");
	m_iMapLoaderDataSetSelected = -1;
	m_sMapFile = "";

	return true;
}

bool MotionViewerApp::handleMapLoaderOK(const CEGUI::EventArgs& e)
{
	// check map file name and dataset selected
	if (m_sMapFile.length() == 0 || m_iMapLoaderDataSetSelected < 0)
		return true;

	// change dataset mapping to current character
	// 1. assign dataset to character
	// 2. load map file
	ViconMotionDataSet* data = m_vViconVisualizers[m_iMapLoaderDataSetSelected]->getDataSet();
	m_vCharacters[m_iCurrCharacterSelected].connectToMotionData(data);
	m_vCharacters[m_iCurrCharacterSelected].loadSkeletonMapping((char*)m_sMapFile.c_str());
	
	// reset variables
	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/ConnectMotionData/MapFile")->setText("N/A");
	m_iMapLoaderDataSetSelected = -1;
	m_sMapFile = "";

	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/ConnectMotionData")->hide();

	return true;
}

bool MotionViewerApp::handleMapLoaderClose(const CEGUI::EventArgs& e)
{
	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/ConnectMotionData")->hide();

	// reset variables
	CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)"Root/ConnectMotionData/MapFile")->setText("N/A");
	m_iMapLoaderDataSetSelected = -1;
	m_sMapFile = "";

	return true;
}